unit VideoOut;

interface

uses
  EZStream,
  SimpleThread, PacketBuffer, WaveOut,
  SysUtils, Classes, Graphics, SyncObjs;

type
  IVideoOut = interface
    ['{768C8F74-B06B-477E-B88B-2E5A0AB64B74}']

    function GetBitmap(ABitmap:TBitmap):boolean;
  end;

  TVideoOut = class (TComponent, IVideoOut)
  private
    FCS : TCriticalSection;
    FEZStreamVideo : IEZStreamVideo;
    FBitmapIsReady : boolean;
    FBitmap: TBitmap;
    FPacketList : TPacketBuffer;
  private
    FSimpleThread : TSimpleThread;
    procedure on_Repeat(Sender:TObject);
  private
    FOnBitmapIsReady: TNotifyEvent;
  public
    constructor Create(AOwner:TComponent; AEZStreamVideo:IEZStreamVideo); reintroduce;
    destructor Destroy; override;

    procedure Init;
    procedure DataIn(AData:pointer; ASize:integer);

    function GetBitmap(ABitmap:TBitmap):boolean;
  published
    property OnBitmapIsReady : TNotifyEvent read FOnBitmapIsReady write FOnBitmapIsReady;
  end;

implementation

{ TVideoOut }

constructor TVideoOut.Create(AOwner: TComponent; AEZStreamVideo: IEZStreamVideo);
begin
  inherited Create(AOwner);

  FEZStreamVideo := AEZStreamVideo;

  FBitmapIsReady := false;

  FCS := TCriticalSection.Create;

  FBitmap := TBitmap.Create;
  FBitmap.PixelFormat := pf32bit;

  FPacketList := TPacketBuffer.Create;

  FSimpleThread := TSimpleThread.Create(on_Repeat);
end;

procedure TVideoOut.DataIn(AData: pointer; ASize: integer);
begin
  FPacketList.Add(AData, ASize);
  FSimpleThread.WakeUp;
end;

destructor TVideoOut.Destroy;
begin
  FSimpleThread.Terminate;

  // TODO:
//  FreeAndNil(FCS);
//  FreeAndNil(FBitmap);
//  FreeAndNil(FPacketList);

  inherited;
end;

function TVideoOut.GetBitmap(ABitmap: TBitmap): boolean;
begin
  FCS.Acquire;
  try
    Result := FBitmapIsReady;
    if not Result then Exit;

    FBitmapIsReady := false;

    ABitmap.Assign(FBitmap);
  finally
    FCS.Release;
  end;
end;

procedure TVideoOut.Init;
begin
  FBitmapIsReady := false;

  FBitmap.Width  := FEZStreamVideo.GetWidth;
  FBitmap.Height := FEZStreamVideo.GetHeight;
end;

procedure TVideoOut.on_Repeat(Sender: TObject);
var
  Data : pointer;
  Size : integer;
begin
  while not FSimpleThread.Terminated do begin
    while FPacketList.GetPacket(Data, Size) do begin
      try
        FCS.Acquire;
        try
          if FEZStreamVideo.DecodeVideo(Data, Size, FBitmap) then begin
             FBitmapIsReady := true;
            if Assigned(FOnBitmapIsReady) then FOnBitmapIsReady(Self);
          end;
        finally
          FCS.Release;
        end;
      finally
        if Data <> nil then FreeMem(Data);
      end;
    end;

    FSimpleThread.SleepTight;
  end;
end;

end.
